package persistence;

import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import model.User;

public class UserDAOJDBC implements UserDAO {

    private final Object lock = new Object();
    private static UserDAOJDBC instance = null;
    private Connection connection = null;
    private static final Logger log = Logger.getLogger(UserDAOJDBC.class.getName());

    public UserDAOJDBC() {
    }

    //@Abraham potencial problema de sincronizacion en la creación del objeto; pueden crearse varios
    public static UserDAOJDBC getInstance() {
        if (instance == null) {
            instance = new UserDAOJDBC();
        }
        return instance;
    }

    @Override
    public boolean connection(String user, String pass, String driver, String url) {
        try {
            Class.forName(driver);
            connection = DriverManager.getConnection(url, user, pass);
        } catch (ClassNotFoundException | SQLException ex) {
            log.log(Level.SEVERE, "Ocurrió un error al intentar conectar con la base de datos", ex);
            return false;
        }
        return true;
    }

    @Override
    public boolean disconnect() {
        try {
            connection.close();
        } catch (SQLException ex) {
            log.log(Level.SEVERE, "No se pudo cerrar la conexión con la base de datos", ex);
            return false;
        }
        return true;
    }

    @Override
    public boolean newUser(User user) {
        if (getUserByEmail(user.getUserEmail()) == null && getUserByNickName(user.getUserNickName()) == null) {
            String query = "INSERT INTO \"USERS\" VALUES (?,?,?,?,?)";
            PreparedStatement statement;
            try {
                synchronized (lock) {
                    statement = connection.prepareStatement(query);
                }
                statement.setString(1, user.getUserName());
                statement.setString(2, user.getUserNickName());
                statement.setString(3, user.getUserEmail());
                statement.setString(4, user.getUserPassword());
                String privileged = "f";
                if (user.isUserPrivileged()) {
                    privileged = "t";
                }
                statement.setString(5, privileged);
                statement.execute();
                return true;
            } catch (SQLException ex) {
                log.log(Level.SEVERE, "Error al crear el usuario", ex);
                return false;
            }
        } else {
            return false;
        }
        //@Abraham falta por cerrar el statement, y lo mismo en los demás metodos
    }

    @Override
    public User getUserByEmail(String userEmail) {
        String query = "SELECT * FROM \"USERS\" WHERE \"USEREMAIL\" = ?";
        PreparedStatement statement;
        ResultSet result = null;
        User user = null;
        try {
            synchronized (lock) {
                statement = connection.prepareStatement(query);
            }
            statement.setString(1, userEmail);
            result = statement.executeQuery();
            while (result.next()) {
                String userPrivileged = result.getString("USERPRIVILEGED");
                boolean privileged = false;
                if (userPrivileged.equals("t")) {
                    privileged = true;
                }
                user = new User(result.getString("USERNAME"), result.getString("USERNICKNAME"),
                        result.getString("USEREMAIL"), result.getString("USERPASSWORD"), privileged);
            }
        } catch (SQLException ex) {
            log.log(Level.WARNING, "Fallo al realizar SELECT contra la Base de Datos", ex);
            user = null;
        } finally {
            if (result != null) {
                try {
                    result.close();
                } catch (SQLException ex2) {
                    log.log(Level.INFO, "No se pudo cerrar el ResultSet del SELECT", ex2);
                }
            }
        }
        return user;
    }

    @Override
    public User getUserByNickName(String userNickName) {
        String query = "SELECT * FROM \"USERS\" WHERE \"USERNICKNAME\" = ?";
        PreparedStatement statement;
        ResultSet result = null;
        User user = null;
        try {
            synchronized (lock) {
                statement = connection.prepareStatement(query);
            }
            statement.setString(1, userNickName);
            result = statement.executeQuery();
            while (result.next()) {
                String userPrivileged = result.getString("USERPRIVILEGED");
                boolean privileged = false;
                if (userPrivileged.equals("t")) {
                    privileged = true;
                }
                user = new User(result.getString("USERNAME"), result.getString("USERNICKNAME"),
                        result.getString("USEREMAIL"), result.getString("USERPASSWORD"), privileged);
            }
        } catch (SQLException ex) {
            log.log(Level.WARNING, "Fallo al realizar SELECT contra la Base de Datos", ex);
            user = null;
        } finally {
            if (result != null) {
                try {
                    result.close();
                } catch (SQLException ex2) {
                    log.log(Level.INFO, "No se pudo cerrar el ResultSet del SELECT", ex2);
                }
            }
        }
        return user;
    }

    @Override
    public Map<String, User> getUserMap() {
        String query = "SELECT * FROM \"USERS\"";
        PreparedStatement statement;
        ResultSet result = null;
        User u;
        Map<String, User> map = new HashMap<>();
        try {
            synchronized (lock) {
                statement = connection.prepareStatement(query);
            }
            result = statement.executeQuery();
            while (result.next()) {
                String userPrivileged = result.getString("USERPRIVILEGED");
                boolean privileged = false;
                if (userPrivileged.equals("t")) {
                    privileged = true;
                }
                u = new User(result.getString("USERNAME"), result.getString("USERNICKNAME"),
                        result.getString("USEREMAIL"), result.getString("USERPASSWORD"), privileged);
                map.put(u.getUserEmail(), u);
            }
        } catch (SQLException ex) {
            log.log(Level.WARNING, "Fallo al realizar SELECT contra la Base de Datos", ex);
            map = null;
        } finally {
            if (result != null) {
                try {
                    result.close();
                } catch (SQLException ex2) {
                    log.log(Level.INFO, "No se pudo cerrar el ResultSet del SELECT", ex2);
                }
            }
        }
        return map;
    }
}
